package com.yuanian.timingwheel.model.task.base;

import com.yuanian.timingwheel.config.JobConfig;
import com.yuanian.timingwheel.model.task.TaskStatus;
import com.yuanian.timingwheel.model.task.executetask.LocalTaskExecutor;
import com.yuanian.timingwheel.model.task.executestragy.ExecutionStrategy;
import com.yuanian.timingwheel.model.task.executestragy.RetryExecutionStrategy;
import com.yuanian.timingwheel.model.task.transaction.TaskTransactionCallback;
import com.yuanian.timingwheel.threadlocal.ThreadLocalEntity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 基础任务
 */
public class BaseTask implements Task, Serializable {

    //任务ID
    protected Long id;

    //业务ID
    protected String businessId;

    //任务类型,1自动0手工
    protected int type;

    //任务状态 1暂停0正常
    protected int status;

    //任务处于的状态
    protected TaskStatus taskStatus;

    //任务需要执行的方法
    protected LocalTaskExecutor localTaskExecutor;

    //任务描述
    protected String taskDesc;

    //执行策略
    protected ExecutionStrategy executionStrategy;

    //具有依赖关系的任务,此任务执行完后再执行
    protected List<BaseTask> attachTaskList;

    //任务信息
    protected TaskExecutionInfo taskExecutionInfo;

    //任务执行结果
    protected TaskExecutionResult taskExecutionResult;

    //任务执行的事务回调
    protected TaskTransactionCallback taskTransactionCallback;

    public BaseTask(String businessId, long executionInterval, long executionRounds, Date executionTime, String taskDesc) {
        this.businessId = businessId;
        this.taskExecutionInfo = new TaskExecutionInfo(executionInterval, executionRounds, executionTime);
        this.taskDesc = taskDesc;
        this.taskTransactionCallback = new TaskTransactionCallback(this);
    }

    public BaseTask(String businessId, long executionInterval, long executionRounds, long executedRounds, Date executionTime, String taskDesc) {
        this.businessId = businessId;
        this.taskExecutionInfo = new TaskExecutionInfo(executionInterval, executionRounds, executedRounds, executionTime);
        this.taskDesc = taskDesc;
        this.taskTransactionCallback = new TaskTransactionCallback(this);
    }

    //任务执行
    public Object execute() {
        ThreadLocalEntity.put("task-execute");
        //是否能运行
        if (this.getTaskInfo().canExecute() || this.getId() == null) {//id为null为附加任务
            //开启编程性事务,为了现实任务和附加任务的事务的一致性
            if (this.getId() != null) {//主任务的进入
                return JobConfig.getInstance().getTransactionTemplate().execute(taskTransactionCallback);
            } else {//附加任务的进入
                return taskTransactionCallback.doOutTransaction();
            }
        } else {
            ThreadLocalEntity.clear();
            return null;
        }

    }

    @Override
    public ExecutionStrategy getExecutionStrategy() {
        if (executionStrategy == null) {
            executionStrategy = new RetryExecutionStrategy();
        }
        return executionStrategy;
    }

    public String getTaskDesc() {
        return taskDesc;
    }

    public void setTaskDesc(String taskDesc) {
        this.taskDesc = taskDesc;
    }

    public void addAttachTask(BaseTask attachTask) {
        if (attachTaskList == null) {
            attachTaskList = new ArrayList<>();
        }
        attachTaskList.add(attachTask);
    }

    public void createTaskMethod(String executionMethod, String beanName, Object[] args) {
        this.localTaskExecutor = new LocalTaskExecutor(executionMethod, beanName, args);
    }

    public TaskExecutionInfo getTaskInfo() {
        return taskExecutionInfo;
    }

    public String getBusinessId() {
        return businessId;
    }

    public void setBusinessId(String businessId) {
        this.businessId = businessId;
    }

    public LocalTaskExecutor getTaskMethod() {
        return localTaskExecutor;
    }

    public void setTaskMethod(LocalTaskExecutor localTaskExecutor) {
        this.localTaskExecutor = localTaskExecutor;
    }

    public void setExecutionStrategy(ExecutionStrategy executionStrategy) {
        this.executionStrategy = executionStrategy;
    }

    public List<BaseTask> getAttachTaskList() {
        return attachTaskList;
    }

    public void setAttachTaskList(List<BaseTask> attachTaskList) {
        this.attachTaskList = attachTaskList;
    }

    public void setTaskInfo(TaskExecutionInfo taskExecutionInfo) {
        this.taskExecutionInfo = taskExecutionInfo;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public TaskExecutionResult getTaskExecutionResult() {
        return taskExecutionResult;
    }

    public void setTaskExecutionResult(TaskExecutionResult taskExecutionResult) {
        this.taskExecutionResult = taskExecutionResult;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public TaskStatus getTaskStatus() {
        return taskStatus;
    }

    public void setTaskStatus(TaskStatus taskStatus) {
        this.taskStatus = taskStatus;
    }

    @Override
    public String toString() {
        return "BaseTask{" +
                "id=" + id +
                ", businessId='" + businessId + '\'' +
                ", type=" + type +
                ", status=" + status +
                ", taskDesc='" + taskDesc + '\'' +
                '}';
    }
}
